package com.sxt.jt808.codec;

import java.util.List;

import com.sxt.jt808.dto.Jt808Msg;
import com.sxt.jt808.dto.MsgHeader;
import com.sxt.jt808.util.BitConverter;

import cn.hutool.core.codec.BCD;
//import cn.hutool.core.codec.BCD;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

//JT808协议常量
//import static com.sxt.jt808.commons.JT808Const.*;
/**
 * @Author: 罗林
 * @Date: 2019-05-15
 * @Description:JT808协议解码器,转义规则: 0x7d 0x01 -> 0x7d
 * 0x7d 0x02 -> 0x7e
 * @Version: 1.0
 */
@Slf4j
public class JT808Decoder extends ByteToMessageDecoder {
	//注意，@Autowired 无法注入
	
	private BitConverter bitConverter = new BitConverter();

	@Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        log.debug("<<<<< ip:{},hex:{}", ctx.channel().remoteAddress(), ByteBufUtil.hexDump(in));
        
        //将byte数据转化为自定义对象
        Jt808Msg msg = this.convertToObject(in);  
       
        if (msg != null) {
            out.add(msg);
        }
    }
    
    /**
     * 
     * @param in
     * @return
     */
    private Jt808Msg convertToObject(ByteBuf in) {
    	if (in.readableBytes() < 12) { //包头最小长度
            return null;
        }
    	//读取数据
    	byte[] raw = new byte[in.readableBytes()];
        in.readBytes(raw);
        //转义
        ByteBuf escape = this.revert(raw);
        //校验(最后一个字节的索引是escape.capacity-1, getByte(i)//读数据)
        
      
        //解码
        return parse(escape);
    	
    }
    

	/**
     * 	将接收到的原始转义数据还原
     *
     * @param raw
     * @return
     */
	private ByteBuf revert(byte[] raw) {
		int len = raw.length;
        ByteBuf buf = ByteBufAllocator.DEFAULT.heapBuffer(len);//Jt808Msg parse方法回收
        for (int i = 0; i < len; i++) {
            //这里如果最后一位是0x7d会导致index溢出，说明原始报文转义有误
            if (raw[i] == 0x7d && raw[i + 1] == 0x01) {
                buf.writeByte(0x7d);
                i++;
            } else if (raw[i] == 0x7d && raw[i + 1] == 0x02) {
                buf.writeByte(0x7e);
                i++;
            } else {
                buf.writeByte(raw[i]);
            }
        }
        return buf;
	}
	/**
	 * 将ByteBuf解析为Jt808Msg对象
	 * @param escape
	 * @return
	 */
	private Jt808Msg parse(ByteBuf bb) {
		
		/**byte： 1字节，8位，有符号
			short：2字节，16位，有符号
			int：  4字节，32位，有符号
			long： 8字节，64位，有符号
			ByteBuf.getshort(0)读取0和1两个字节的组合
		*/
		Jt808Msg msg = null;
		
		try {
			msg = new Jt808Msg();
			//
			MsgHeader msgHeader = this.parseHeader(bb);
			// 验证包体长度
			int msgBodyByteStartIndex = 12;
			// 2. 消息体
			// 有子包信息,消息体起始字节后移四个字节:消息包总数(word(16))+包序号(word(16))
			if (msgHeader.isHasSubPackage()) {
				msgBodyByteStartIndex = 16;
			}
			//
			ByteBuf msgBodyByteBuf = bb.slice(msgBodyByteStartIndex, msgHeader.getMsgBodyLength());
			//解析消息体字节数组
			byte[] msgBodyBytes = msgBodyByteBuf.array();
			//验证包体长度
			if (msgHeader.getMsgBodyLength() != msgBodyByteBuf.readableBytes()) {
				throw new RuntimeException("包体长度有误");
			}
			msg.setMsgHeader(msgHeader);
			msg.setMsgBodyByteBuf(msgBodyByteBuf);
			msg.setMsgBodyBytes(msgBodyBytes);
			return msg;
		} catch (Exception e) {
			// TODO: handle exception
			return msg;
		} finally {
			// 释放
			ReferenceCountUtil.safeRelease(bb);
		}
		
	}
	
	/**
	 * 解析头消息
	 * @param msgByteBuf
	 * @return
	 */
	private MsgHeader parseHeader(ByteBuf msgByteBuf) {
		MsgHeader header = new MsgHeader(); 
		header.setMsgId(msgByteBuf.getShort(0));// 消息体ID 2字节

		// ========消息体属性========
		int msgBodyProps = msgByteBuf.getShort(2);
		header.setMsgBodyPropsField(msgBodyProps);// byte[2-3] 2字节
		// [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度)
		header.setMsgBodyLength(msgBodyProps & 0x1ff);// 消息体长度
		// [10-12] 0001,1100,0000,0000(1C00)(加密类型)
		header.setEncryptionType((msgBodyProps & 0xe00) >> 10);// 数据加密方式
		// [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包)
		header.setHasSubPackage(((msgBodyProps & 0x2000) >> 13) == 1);// 是否分包
		header.setReservedBit(((msgBodyProps & 0xc000) >> 14) + "");// 保留位[14-15]

		// =====消息包封装项========
		if (header.isHasSubPackage()) {
			header.setPackageInfoField(msgByteBuf.getInt(12));// 消息包封装项字段
			header.setTotalSubPackage(msgByteBuf.getShort(12));// 消息包总数(word(16))
			header.setSubPackageSeq(msgByteBuf.getShort(14));// 包序号(word(16))这次发送的这个消息包是分包中的第几个消息包, 从 1 开始
		}
		
		// 终端手机号 6字节
		byte[] bytes = new byte[6];
		msgByteBuf.getBytes(4, bytes);
		header.setTerminalPhone(BCD.bcdToStr(bytes)); //
		System.out.println(this.bitConverter.bcd2String(bytes));
		
		// 消息流水号 2字节
		header.setFlowId(msgByteBuf.getShort(10));
		return header;
	}

}